package cn.gem.rainbow.cfg.token;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

/**
 *

 服务器认证以后，生成一个 JSON 对象发回给用户，以后用户与服务端通信的时候，都要发回这个 JSON 对象。
 服务器完全只靠这个对象认定用户身份。
 为了防止用户篡改数据，服务器在生成这个对象的时候，会加上签名。
 也就是说服务器就不保存任何 session 数据了，即服务器变成无状态了，从而比较容易实现扩展。
 简单来说，就是通过一定规范来生成 token，然后可以通过解密算法逆向解密 token，这样就可以获取用户信息


 优点：生产的 token 可以包含基本信息，比如 id、用户昵称、头像等信息，避免再次查库；存储在客户端，不占用服务端的内存资源
 缺点：token 是经过 base64 编码，所以可以解码，因此 token 加密前的对象不应该包含敏感信息（如用户权限，密码等



 JWT 格式组成：头部+负载+签名 ( header + payload + signature )
 头部：主要是描述签名算法。
 负载：主要描述是加密对象的信息，如用户的 id 等，也可以加些规范里面的东西，如 iss 签发者，exp 过期时间，sub 面向的用户。
 签名：主要是把前面两部分进行加密，防止别人拿到 token 进行base 解密后篡改 token
 */
public class JwtUtil {
    // 主题
    public static final String SUBJECT = "Authorization";

    // 秘钥
    public static final String SECRET_KEY = "Rookie666";

    // 过期时间
    public static final long EXPIRE = 1000 * 60 * 60 * 24 * 7;  //过期时间，毫秒，一周

    public static String createJwt(TokenUser user){
        if (user == null ||
                user.getUserId() == null ||
                user.getUserName() == null) {

            return null;
        }

        String token = Jwts.builder()
                //token主题
                .setSubject(SUBJECT)
                //token受众--SPA 前端单页WEB应用
                .setAudience("SPA")
                //claim负载信息---不敏感的用户信息
                .claim("uid", user.getUserId())
                .claim("uname", user.getUserName())
                //签发人--后端服务
                .setIssuer("backend")
                //签发时间
                .setIssuedAt(new Date())
                //过期时间(这里指的是token内容失效时间, 这里的失效指到期之后不再解析/校验该token字符串)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                //使用密钥和HS256加密 （SECRET_KEY是加密的钥匙,HS256是加密的算法）
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
        return token;
    }


    // 校验 JWT
    public static Claims checkJWT(String token) {

        try {
            final Claims claims = Jwts.parser()
                    //解密的钥匙
                    .setSigningKey(SECRET_KEY)
                    //要解析的token字符串
                    .parseClaimsJws(token)
                    .getBody();
            return claims;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
